"""
python p2_solution_deap_2.py
"""
import json
import os
from deap import base, creator, tools, algorithms
import random

# 读取仓库信息
def read_warehouse_data():
    with open('../fujian/fujian3/origin_data/warehouse.json') as f:
        return json.load(f)

# 读取品类平均库存量
def read_category_inventory():
    with open('../fujian/fujian3/data_from_p1/all_average_inventory.json') as f:
        return {d['category_id']: d['average_inventory'] for d in json.load(f)}

# 读取品类平均销量
def read_category_sales():
    with open('../fujian/fujian3/data_from_p1/all_average_sales.json') as f:
        return {d['category_id']: d['average_sales'] for d in json.load(f)}

warehouses = read_warehouse_data()
category_inventories = read_category_inventory()
category_sales = read_category_sales()

creator.create("FitnessMin", base.Fitness, weights=(-1.0,))
creator.create("Individual", list, fitness=creator.FitnessMin)

toolbox = base.Toolbox()

def generate_random_warehouse():
    return random.choice(range(len(warehouses)))

toolbox.register("attr_int", generate_random_warehouse)
toolbox.register("individual", tools.initRepeat, creator.Individual, toolbox.attr_int, n=len(category_inventories))
toolbox.register("population", tools.initRepeat, list, toolbox.individual)

def evaluate(individual):
    total_cost = 0
    warehouse_inventories = [0] * len(warehouses)
    warehouse_sales = [0] * len(warehouses)
    
    # Calculate warehouse inventory and sales
    for category_index, warehouse_index in enumerate(individual):
        warehouse_inventories[warehouse_index] += category_inventories[str(category_index + 1)]
        warehouse_sales[warehouse_index] += category_sales[str(category_index + 1)]
    
    # Check for constraint violations and calculate cost
    for warehouse_index, warehouse in enumerate(warehouses):
        if (warehouse_inventories[warehouse_index] > warehouse['max_inventory'] or 
            warehouse_sales[warehouse_index] > warehouse['max_sales']):
            return (float('inf'),)  # Return a tuple to avoid TypeError
        if warehouse_inventories[warehouse_index] > 0:
            total_cost += warehouse['daily_cost']
    
    return (total_cost,)  # Ensure this is a tuple


toolbox.register("evaluate", evaluate)
toolbox.register("mate", tools.cxTwoPoint)
toolbox.register("mutate", tools.mutUniformInt, low=0, up=len(warehouses)-1, indpb=0.2)
toolbox.register("select", tools.selTournament, tournsize=3)

population_size = 100
generations = 50

pop = toolbox.population(n=population_size)

stats = tools.Statistics(lambda ind: ind.fitness.values)
stats.register("min", min)
stats.register("avg", lambda x: sum(x) / len(x))

logbook = tools.Logbook()
logbook.header = "gen", "evals", "min", "avg"

for gen in range(generations):
    offspring = toolbox.select(pop, len(pop))
    offspring = list(map(toolbox.clone, offspring))
    for child1, child2 in zip(offspring[::2], offspring[1::2]):
        if random.random() < 0.7:
            toolbox.mate(child1, child2)
            del child1.fitness.values
            del child2.fitness.values
    for mutant in offspring:
        if random.random() < 0.2:
            toolbox.mutate(mutant)
            del mutant.fitness.values
    invalid_ind = [ind for ind in offspring if not ind.fitness.valid]
    fitnesses = map(toolbox.evaluate, invalid_ind)
    for ind, fit in zip(invalid_ind, fitnesses):
        ind.fitness.values = fit
    pop[:] = offspring
    record = stats.compile(pop)
    logbook.record(gen=gen, evals=len(invalid_ind), **record)
    print(logbook.stream)

best_individual = tools.selBest(pop, 1)[0]

result = []
for category_index, warehouse_index in enumerate(best_individual):
    result.append({
        "category_id": str(category_index + 1),
        "warehouse_id": warehouses[warehouse_index]['warehouse_id']
    })

# 创建输出文件夹
output_folder = '../fujian/fujian3/deap/'
os.makedirs(output_folder, exist_ok=True)

# 输出结果 JSON
with open(os.path.join(output_folder, 'result.json'), 'w') as f:
    json.dump(result, f, indent=4)

# 计算总成本并输出到文件
total_cost = 0
warehouse_inventories = [0] * len(warehouses)
warehouse_sales = [0] * len(warehouses)
for category_index, warehouse_index in enumerate(best_individual):
    warehouse_inventories[warehouse_index] += category_inventories[str(category_index + 1)]
    warehouse_sales[warehouse_index] += category_sales[str(category_index + 1)]
for warehouse_index, warehouse in enumerate(warehouses):
    if warehouse_inventories[warehouse_index] > 0:
        total_cost += warehouse['daily_cost']
with open(os.path.join(output_folder, 'all_cost.txt'), 'w') as f:
    f.write(str(total_cost))

# 计算库存量利用率并输出到 JSON 文件
inventory_utilization = []
for warehouse_index, warehouse in enumerate(warehouses):
    if warehouse['max_inventory'] > 0:
        utilization_rate = warehouse_inventories[warehouse_index] / warehouse['max_inventory']
    else:
        utilization_rate = 0
    inventory_utilization.append({
        "warehouse_id": warehouse['warehouse_id'],
        "utilization_rate_of_inventory": utilization_rate
    })
with open(os.path.join(output_folder, 'all_utilization_rate_inventory.json'), 'w') as f:
    json.dump(inventory_utilization, f, indent=4)
